//Copyright (c) 2013 Tilo Szepan, Immo Wache
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
//documentation files (the "Software"), to deal in the Software without restriction, including without limitation
//the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
//and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all copies or substantial portions 
//of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
//CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//DEALINGS IN THE SOFTWARE.

using System;
using System.Text;
using System.Net;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.Specialized;
using Gtk;
using Gdk;
using System.IO;
using MonoMobile.Dialogs.Remote.Discovery;

namespace DuinoClient
{
	public class JSEditor : Gtk.Window
	{
//		MainWindow _main;
        WebClient client;
		Button btn_apply;

        TextView text_out, text_in;
		HBox cmdLine;
        ComboBoxEntry pathSelect, methodSelect;

		public JSEditor (MainWindow main, string initAddr) : 
				base(Gtk.WindowType.Toplevel)
		{
//			_main = main;
			Title = "JSEditor";
			WindowPosition = Gtk.WindowPosition.Center;
			BorderWidth = (uint)6;
			var vbox1 = new Gtk.VBox ();
			vbox1.Spacing = 6;

			text_out = new TextView();
			var sw1 = new ScrolledWindow();
			sw1.Add(text_out);
			sw1.ShadowType = ShadowType.EtchedIn;
			text_in = new TextView();
			text_in.Editable = false;
			text_in.ModifyBase(StateType.Normal, new Color(180, 180, 180));
			var sw2 = new ScrolledWindow();
			sw2.Add(text_in);
			sw2.ShadowType = ShadowType.EtchedOut;
			vbox1.PackEnd(Buttons(), false, false, 0);
			vbox1.PackEnd(sw2, true, true, 5);
			vbox1.PackEnd(sw1, true, true, 5);
			vbox1.PackStart(CmdLine(initAddr), false, false, 0);
			Add (vbox1);

			DeleteEvent += OnDeleteEvent;
			Child.ShowAll ();
			DefaultWidth = 400;
			DefaultHeight = 300;
            client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
            client.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompleted);
		}
		Widget Buttons()
		{
			btn_apply = new Gtk.Button ();
			btn_apply.Label = "Send";
//			btn_apply.Sensitive = false;
			var btn_cancel = new Gtk.Button ();
			btn_cancel.Label = "Cancel";

			var hbox = new Gtk.HBox ();
			hbox.Spacing = 6;
			hbox.PackEnd(btn_cancel, false, false, 0);
			hbox.PackEnd(btn_apply, false, false, 0);

			btn_cancel.Clicked += HandleCancelClicked;
			btn_apply.Clicked += HandleApplyClicked;

			return hbox;
		}
		Widget CmdLine(string addr)
		{
			cmdLine = new HBox(false, 6);
			if(String.IsNullOrEmpty(addr)) addr = "http://";
			pathSelect = new ComboBoxEntry(new[]{addr});
			pathSelect.Active = 0;
			pathSelect.Entry.Activated += HandleApplyClicked;
			methodSelect = new ComboBoxEntry(new[] { "GET", "PUT", "POST" });
			methodSelect.Active = 0;
			methodSelect.SetSizeRequest(80, 25);
			cmdLine.PackEnd(methodSelect, false, false, 6);
			cmdLine.Add(pathSelect);
			return cmdLine;
		}

		void HandleCancelClicked (object sender, EventArgs e)
		{
			if(client.IsBusy){
				client.CancelAsync();
				text_in.Buffer.Text = "canceled";
			}else OnDeleteEvent(sender, e);
		}
		void HandleApplyClicked (object sender, EventArgs e)
		{
            try
            {
                BeginWait();
                if (methodSelect.Active != 0)
                {
                    client.Headers.Add("Content-Type: text/js");
                    client.UploadStringAsync(new Uri(pathSelect.ActiveText), methodSelect.ActiveText, text_out.Buffer.Text);
                }
                else
                    client.DownloadStringAsync(new Uri(pathSelect.ActiveText));
            }
            catch (Exception ex)
            {
				HandleExceptions(ex);
            }
		}

        void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
        {
            if(CheckArgs(e))
				text_in.Buffer.Text = e.Result;//.Replace("\n", Environment.NewLine);
        }
        void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (CheckArgs(e))
            {
				text_in.Buffer.Text = e.Result;//.Replace("\n", Environment.NewLine);
                text_out.Buffer.Text = e.Result;
            }
        }
        bool CheckArgs(AsyncCompletedEventArgs e)
        {
            EndWait();
            if (e.Error != null || e.Cancelled)
            {
                HandleExceptions(e.Error);
                return false;
            }
            return true;
        }
        void BeginWait()
        {
            btn_apply.Sensitive = false;
			cmdLine.Sensitive = false;
			text_in.Sensitive = false;
			text_out.Sensitive = false;
//			GdkWindow.Cursor = new Cursor(CursorType.Watch);
        }
        void EndWait()
        {
            btn_apply.Sensitive = true;
			cmdLine.Sensitive = true;
			text_in.Sensitive = true;
			text_out.Sensitive = true;
//			GdkWindow.Cursor = new Cursor(CursorType.Arrow);
        }
		void HandleExceptions(Exception ex)
		{
			if(ex == null) return;
			Console.WriteLine (ex.StackTrace);
			Gdk.Threads.AddIdle(0, ()=>{
				var md = new MessageDialog(this, DialogFlags.DestroyWithParent, MessageType.Error, ButtonsType.Close, false, ex.Message);
				md.Title = "an error has occurred";
				md.Run();
				md.Destroy();
				return false;
			});
		}
		protected void OnDeleteEvent (object sender, EventArgs a)
		{
			client.CancelAsync();
			client.Dispose();
			Destroy();
			Dispose();
		}
	}
}

